package com.aqa.concurrent;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.IntStream;

/**
 * 《大型网站系统与Java中间件实践》第一章1.2.2.3小节的一个讨论：
 * <p>
 * 即使是使用了安全Map类型，但是在Map之外的操作时不具备线程安全的。
 * 使用了synchronized则保证了一段代码块范围的执行是线程安全的。
 * </p>
 * <p>
 * 下面的代码需要注意的是：线程的join()不能紧随线程的start()方法，
 * 不然会按线程顺序一个个执行完毕，看不出并发错误。因为join是让相应线程
 * 持有CPU执行，所以此处代码时将线程保存在List中，在所有线程start()
 * 之后，才对所有线程进行join()
 * </p>
 * @author Administrator
 *
 */
public class SafeAndUnSafeMap {
	//非并发Map
	private Map<String,Integer> map = new HashMap<>();
	//并发Map
	private Map<String,Integer> conMap = new ConcurrentHashMap<>();
	/**
	 * 使用了 synchronized 的代码块，永远线程并发安全
	 * @param key map的Key
	 */
	public synchronized void testAddOnUnSafeMap(String key) {
		Integer value = map.get(key);
		if (value == null) {
			map.put(key, 1);
		}else {
			map.put(key, value+1);
		}
	}

	/**
	 * 即使内部使用了并发Map，但是出去Map本身的put、get操作是线程安全外
	 * 其他的执行均非线程安全
	 * @param key 并发Map的key
	 */
	public void testAddOnSafeMap(String key) {
		Integer value = conMap.get(key);
		if (value == null) {
			conMap.put(key, 1);
		}else {
			conMap.put(key, value+1);
		}
	}
	/* 此两个参数用于判断所有线程是否执行完毕，代码修改后不使用 */
//	volatile boolean unSafeThreadIsDone = false;
//	volatile boolean safeThreadfeIsDone = false;

	public static void main(String[] args) {
		SafeAndUnSafeMap test = new SafeAndUnSafeMap();
		test.run();
	}

	private void run() {
		SafeAndUnSafeMap test = new SafeAndUnSafeMap();
		List<Thread> unsafeThreadList = new ArrayList<Thread>(10);
		/*启动10个线程，每个线程循环1000次put、get操作，查看结果 */
		IntStream.range(1, 11).forEach((i) -> {
			Thread nThread = new Thread(() -> {
				IntStream.range(1, 1001).forEach((j) -> {
					test.testAddOnUnSafeMap("unSafeMapKey");
				});
				System.out.println(" >>>>> "+Thread.currentThread().getName()+" done!");
//				test.unSafeThreadIsDone = true;
			},"UnSafeThread - "+i);
			nThread.start();
			unsafeThreadList.add(nThread);
		});
		/*将线程list进行反转，然后进行join，希望以此增加线程的混乱执行 */
		Collections.reverse(unsafeThreadList);
		unsafeThreadList.stream().forEach((thread) -> {
			try {
				thread.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		//==================================================
		/*启动10个线程，每个线程循环1000次put、get操作，查看结果 */
		List<Thread> safeThreadlist = new ArrayList<Thread>(10);
		IntStream.range(1, 11).forEach((i) -> {
			Thread snThread = new Thread(() -> {
				IntStream.range(1, 1001).forEach((j) -> {
					test.testAddOnSafeMap("safeMapkey");
				});
				System.out.println(" >>>>> "+Thread.currentThread().getName()+" done!");
//				test.safeThreadfeIsDone = true;
			},"SafeThread - "+i);
			snThread.start();
			safeThreadlist.add(snThread);
		});
		Collections.reverse(safeThreadlist);
		safeThreadlist.stream().forEach((thread)->{
			try {
				thread.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
//		outer:
//			while(true) {
//				while(test.unSafeThreadIsDone && test.safeThreadfeIsDone) {
//					System.out.println(test.map);
//					System.out.println(test.conMap);
//					break outer;
//				}
//			}
		System.out.println(test.map);
		System.out.println(test.conMap);
		System.out.println("------------------Application done------------------");
	}
}
